const { Service } = require('egg');
const { sm4 } = require('sm-crypto');
const { v4: uuidV4 } = require('uuid');
const svgCaptcha = require('svg-captcha');
const jwt = require('jsonwebtoken');
const moment = require('moment');

const table_name = 'permission';
class HomeService extends Service {

  async init() {
    const knex = this.app.knex;
    try {
      const list = [];
      const { stack } = this.app.router;
      const time = moment();

      const interface_list = await knex(table_name).select('uuid', 'url', 'key').where({ model: 'AUTH', is_delete: 0 });

      for (const s of stack) {
        const method = s.methods[s.methods.length - 1];
        const key = `${method}${s.path.replace(/\//g, ':')}`;
        const interfaces = interface_list.find(f => {
          return f.key === key;
        });

        if (!interfaces) {
          const obj = {
            uuid: uuidV4().replace(/-/g, ''),
            model: 'AUTH',
            name: s.name,
            key: `${method}${s.path.replace(/\//g, ':')}`,
            url: s.path,
            method,
            type: 1,
            status: 0,
            parent_id: '-1',
            create_time: moment(time).format('YYYY-MM-DD HH:mm:ss'),
            update_time: moment(time).format('YYYY-MM-DD HH:mm:ss'),
            create_by: '-1',
            update_by: '-1',
            is_delete: 0,
          };

          list.push(obj);
        }
      }


      if (list.length !== 0) {
        await knex(table_name).insert(list);
      }

      return 'success';
    } catch (error) {
      console.log(error);
      throw new Error('service错误');
    }
  }


  // 获取图形验证码
  async code(visitor) {
    try {
      const id = visitor ? visitor : uuidV4();
      const options = {
        size: 4, // 4个字母
        noise: 2, // 干扰线2条
        color: true, // 文字颜色
        background: '#666', // 背景颜色
      };

      const { text, data } = svgCaptcha.create(options);
      // const existence_in = 5 * 60;
      const existence_in = 60 * 60 * 8;
      // 设置图形验证码有效时间
      await this.app.redis.set(`code:${id}`, text, 'EX', existence_in);
      return {
        img: data,
        text,
        visitor_id: id,
        existence_in,
      };
    } catch (error) {
      throw error;
    }
  }

  // 登录
  async login(login_name, password, code, visitor) {
    const ctx = this.ctx;
    const app = this.app;
    try {
      const smConfig = this.app.config.sm;

      // 先校验验证码
      const codeStr = await this.app.redis.get(`code:${visitor}`);

      if (code.toLowerCase() !== codeStr.toLowerCase()) {
        throw new Error('验证码错误');
      }

      // 校验用户以及用户名
      const [ user ] = await this.app.knex
        .select('t1.uuid', 't1.name as alias', 't1.login_name', 't1.password', 't3.uuid as role_id', 't3.name as role_name')
        .from('user as t1')
        .leftJoin('user_role_relationship as t2', function() {
          this.on('t1.uuid', '=', 't2.user_id');
        })
        .leftJoin('role as t3', function() {
          this.on('t2.role_id', '=', 't3.uuid');
        })
        .whereRaw(`t1.login_name = '${login_name}' and t1.is_delete = 0 and t2.is_delete = 0`);
      if (!user) {
        throw new Error('当前用户不存在');
      }
      const decrypt = sm4.encrypt(password, smConfig.key, { mode: smConfig.mode, iv: smConfig.iv });

      if (decrypt !== user.password) {
        throw new Error('密码错误');
      }


      // access_token
      const access_token = jwt.sign({
        id: user.uuid,
        login_name: user.login_name,
        name: user.name,
        role_id: user.role_id,
        role_name: user.role_name,
      }, app.config.jwt,
      { expiresIn: '5m' }
      );

      const refresh_token = jwt.sign({
        id: user.uuid,
      }, app.config.jwt);

      await this.app.redis.set(`refresh:${user.uuid}`, refresh_token, 'EX', 24 * 60 * 60);
      await this.app.redis.set(`access:${user.uuid}`, access_token, 'EX', 60 * 60 * 12);

      return {
        access_token: `Bearer ${access_token}`,
        refresh_token: `Bearer ${refresh_token}`,
      };
    } catch (error) {
      throw error;
    }
  }

  // 刷新令牌
  async refresh(refresh_token) {
    const ctx = this.ctx;
    const app = this.app;
    try {
      const r_token = refresh_token.replace('Bearer ', '');
      const decode = jwt.decode(r_token);
      const [ user ] = await this.app.knex('user').select('uuid', 'name', 'login_name').where({ uuid: decode.id });


      const access_token = jwt.sign({
        id: user.uuid,
        login_name: user.login_name,
        name: user.name,
      }, app.config.jwt,
      { expiresIn: '5m' });

      await this.app.redis.set(`refresh:${user.uuid}`, refresh_token, 'EX', 24 * 60 * 60);
      await this.app.redis.set(`access:${user.uuid}`, access_token, 'EX', 60 * 60 * 12);

      return {
        access_token: `Bearer ${access_token}`,
        refresh_token: `Bearer ${refresh_token}`,
      };
    } catch (error) {
      throw error;
    }
  }

  // 登出
  async logout(refresh_token) {
    try {
      const r_token = refresh_token.replace('Bearer ', '');
      const decode = jwt.decode(r_token);

      await this.app.redis.del(`refresh:${decode.id}`);
      await this.app.redis.del(`access:${decode.id}`);
      return;
    } catch (error) {
      throw error;
    }
  }


  // 检查是否拥有权限
  async checkout(key, role_id) {
    try {
      let result = false;


      if (role_id === '-1') {
        result = true;
      } else {
        const per = await this.app.knex
          .select('t1.id')
          .from('role_permission_relationship as t1')
          .leftJoin('permission as t2', function() {
            this.on('t1.pid', '=', 't1.uuid');
          })
          .whereRaw(`t1.is_delete = 0 and t2.key = ${key} and t1.r_id = ${role_id} and t2.is_delete = 0`);

        if (per) {
          result = true;
        }
      }

      return result;
    } catch (error) {
      throw error;
    }
  }
}

module.exports = HomeService;
